<?php

declare(strict_types=1);

namespace App\Service;

use App\Job\PushActivityMaterialJob;
use App\Job\PushAttentionJob;
use App\Models\CommodityActivity;
use Carbon\Carbon;
use Hyperf\AsyncQueue\Driver\DriverFactory;
use Hyperf\Database\Model\Builder;
use Hyperf\Database\Model\Collection;
use Hyperf\Logger\LoggerFactory;

class QueueService
{
    protected $driver;

    protected $logger;

    public function __construct(DriverFactory $driverFactory, LoggerFactory $loggerFactory)
    {
        $this->driver = $driverFactory->get('default');
        $this->logger = $loggerFactory->get('log', 'default');
    }

    /**
     * 推送活动素材
     * @param $activityId
     * @param string $openIds
     */
    public function pushActivity($activityId = null, $openIds = '')
    {
        $this->logger->info('推送活动素材');

        // 查询活动
        $now = Carbon::now();
        CommodityActivity::query()
            ->with('materials.attachments')
            ->when($activityId, function (Builder $builder, $activityId) {
                // 当指定活动 ID 时
                $builder->where('id', $activityId);
            })
            ->when($activityId === null, function (Builder $builder) use ($now) {
                $builder
                    ->whereIn('push_setting', [
                        CommodityActivity::PUSH_SETTING_NOW,
                        CommodityActivity::PUSH_SETTING_REGULARLY,
                        CommodityActivity::PUSH_SETTING_DAILY
                    ])
                    ->where('specify_the_push_time', $now->format('H:i') . ':00');
            })
            ->where('panic_buying_start_time', '<=', $now)
            ->where('panic_buying_end_time', '>', $now)
            ->where('status', CommodityActivity::STATUS_PUT_ON_SHELF)
            ->chunk(50, function (Collection $result) use ($now, $openIds) {
                $result
                    // 不指定人员时, 要判断活动推送时间
                    ->when($openIds === null, function ($result) use ($now) {
                        return $result->filter(function ($item) use ($now) {
                            // 指定 日期时间 && 日期是同一天
                            $specifiedDateAndTime = $item['push_setting'] === CommodityActivity::PUSH_SETTING_REGULARLY
                                && $now->isSameAs('Y-m-d', Carbon::createFromFormat('Y-m-d', $item['specify_the_push_date']));

                            return $specifiedDateAndTime || ($item['push_setting'] === CommodityActivity::PUSH_SETTING_DAILY); // || 每日指定时间点推送
                        });
                    })
                    ->each(function (CommodityActivity $activity) use ($openIds, $now) {
                        $delay = 0;
                        foreach ($activity->materials as $material) {
                            // 推送活动素材
                            $this->driver->push(new PushActivityMaterialJob($material->toArray(), $openIds), $delay);
                            $delay += 2; // 根据活动素材 每条间隔两秒来推送延时队列
                        }

                        // 如果是"所有"用户,更新活动最后推送时间
                        $openIds !== '' && $activity->update(['last_push_time' => $now]);
                    });
            });
    }

    public function pushAttention()
    {
        $this->driver->push(make(PushAttentionJob::class));
    }
}
